
#include "Managers/EntityManager.h"
#include "Managers/ComponentsManager.h"

#include "Player/PlayerData.h"
#include "Log.h"
#include "Utils/Utils.h"

#include <filesystem>
#include <fstream>
#include <functional>

#include "GameSingleton.h"
#include "GameRegistry.hpp"


namespace PocketSurvival
{
    EntityManager::EntityManager() : m_endEntityID(1) {}
    EntityManager::~EntityManager(){}

    void EntityManager::loadGame()
    {
        loadEssentitalFiles("./content/entity/");
        loadEssentitalFiles("./content/blockEntity/");
    }

    void EntityManager::addEssentialData(const std::string &entityName, const nlohmann::json &jsonData)
    {
        if(m_entityEssentialData.find(entityName) == m_entityEssentialData.end())
        {
            Log::Info(fmt::format("加载基础实体数据 {}", entityName));
            m_entityEssentialData[entityName] = jsonData;
            return;
        }
        throw std::logic_error(fmt::format("基础实体数据 {} 已经存在，不能重复添加", entityName));
    }


    void EntityManager::loadEssentitalFiles(const std::string &path)
    {
        if(std::filesystem::exists(path) == false)
        {
            throw std::runtime_error(fmt::format("没有找到 {} 这个文件夹", path));
        }
        // 遍历该文件夹下面的所有文件
        auto begin = std::filesystem::recursive_directory_iterator(path);   // 获取文件系统迭代器
        auto end = std::filesystem::recursive_directory_iterator();         // end迭代器

        std::vector<std::string> vecStr;
        for (auto it = begin; it != end; it++)
        {
            if(std::filesystem::is_regular_file(*it))
            {
                // 切割文件名称，并且需要以.json结尾的文件才会进行加载
                std::string fileName = it->path().filename().string();
                vecStr.clear();
                Utils::StringSplit(fileName, ".", vecStr);

                if(vecStr.size() >= 2 && vecStr[vecStr.size() - 1] == "json")
                {
                    std::string jsonText;
                    if(Utils::LoadTextFile(fmt::format("{}/{}", path, fileName), jsonText) == true)
                    {
                        nlohmann::json jsonData = nlohmann::json::parse(jsonText);
                        std::string entityName = jsonData["ObjectName"].get<std::string>();

                        addEssentialData(entityName, jsonData);
                    }
                }
            }
        }
    }


    void EntityManager::replaceEssentialData(const std::string &entityName, const nlohmann::json &jsonData)
    {
        bool isFound = m_entityEssentialData.find(entityName) != m_entityEssentialData.end();
        m_entityEssentialData[entityName] = jsonData;
        if(isFound == false)
        {
            Log::Warn(fmt::format("要提换的实体 {} 不存在，不过新的数据也已经加载", entityName));
        }
        else
        {
            Log::Info(fmt::format("成功提换的实体 {} 的基础数据", entityName));
        }
    }


    entt::entity EntityManager::createEntityByName(const std::string &essentityEntityName)
    {
        nlohmann::json essentialJson;
        if (tryGetEntityEssentialData(essentityEntityName, essentialJson))
        {
            entt::entity newEntity = createNewEntity();
            GameSingleton::componentsManager->entityAddComponents(newEntity, essentialJson);
            return newEntity;
        }
        return entt::null;
    }


    entt::entity EntityManager::createEntityByEssentitalData(const nlohmann::json &essentialJson)
    {
        entt::entity newEntity = createNewEntity();
        GameSingleton::componentsManager->entityAddComponents(newEntity, essentialJson);
        return newEntity;
    }

    /***********************************************************************************************************
     * @brief 创建一个空的新实体
     * @return 新建出来的实体，此时实体是空实体，没有任何组件在里面
    ***********************************************************************************************************/
    entt::entity EntityManager::createNewEntity()
    {
        std::lock_guard<SpinLock> lk(m_entityIDLock);
        int32_t entityID = m_endEntityID;
        if(m_recycleEntityIDQueue.try_dequeue(entityID) == false)
        {
            m_endEntityID++;
        }
        return GameSingleton::gameRegistry->create((entt::entity)entityID);
    }

    /***********************************************************************************************************
     * @brief 销毁并回收实体，空实体回收会导致崩服
     * @param entity 要进行销毁的实体，会释放实体内的组件，然后进行销毁并回收处理，回收后改实体将不可用
    ***********************************************************************************************************/
    void EntityManager::destoryEntity(entt::entity entity)
    {
        GameSingleton::componentsManager->entityRemoveComponents(entity);
        GameSingleton::gameRegistry->destroy(entity);

        m_entityIDLock.lock();
        m_recycleEntityIDQueue.enqueue((int32_t)entity);
        m_entityIDLock.unlock();
    }

} // namespace PocketSurvival
